package com.cc.springboot_test.monitor;

import com.alibaba.fastjson.JSONObject;
import com.cc.springboot_test.bean.common.LogInfo;
import com.cc.springboot_test.bean.common.TableData;
import com.cc.springboot_test.mapper.dao.LogInfoMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

@Component
public class LogMonitor {
    private Logger logger = LoggerFactory.getLogger(LogMonitor.class);

    private final AtomicBoolean isHandling = new AtomicBoolean(false);

    private BlockingDeque<LogInfo> queue = new LinkedBlockingDeque<>(1 << 16);

    @Autowired
    private LogInfoMapper logInfoMapper;

    private ExecutorService executor = Executors.newSingleThreadExecutor();

    public void addLogInfo(LogInfo log) {
        try {
            if (queue.offer(log, 10, TimeUnit.MILLISECONDS)) {
                handleQueue();
            } else {
                logger.warn("log insert queue more than 10ms, log={}", JSONObject.toJSONString(log));
                logInfoMapper.insert(log);
            }
        } catch (InterruptedException e) {
            logger.error("log insert error: ", e);
        }
    }

    public void shutdown() {
        executor.shutdown();
    }

    private void handleQueue() {
        if (!isHandling.compareAndSet(false, true)) {
            return;
        }

        executor.execute(new Runnable() {
            @Override
            public void run() {
                TableData<LogInfo> tableData = new TableData<LogInfo>();
                List<LogInfo> logs = new ArrayList<LogInfo>(100);

                LogInfo log = null;
                int index = 0;
                try {
                    if (queue.size() >= 100) {
                        while (index++ < 100) {
                            logs.add(queue.poll());
                        }
                    } else {
                        while ((log = queue.poll()) != null && index++ < 100) {
                            logs.add(log);
                        }
                    }
                    logInfoMapper.inserts(tableData);
                } catch (Throwable e) {
                    logger.error("log inserts error: ", e);
                } finally {
                    isHandling.set(false);
                    if (queue.size() > 0) {
                        handleQueue();
                    }
                }
            }
        });
    }
}
